#include "tools/image_viewer.hpp"
#include <cmath>
#include <algorithm>
#include <vector>
#include <mutex>
#include <iostream>
#include <thread>
#include <chrono>
#include <future>

namespace toolsLib
{

// 顶点着色器源代码 - 用于将图像像素坐标转换为屏幕坐标
const char* vertex_shader_src = R"glsl(
#version 330 core
layout(location = 0) in vec2 aPos;   // 输入：图像像素坐标位置
layout(location = 1) in vec2 aTex;   // 输入：纹理坐标
out vec2 vTex;                       // 输出：传递给片段着色器的纹理坐标
uniform vec2 uWinSize;               // 窗口大小（像素）
uniform vec2 uImgSize;               // 图像大小（像素）
uniform vec2 uOffset;                // 图像坐标中的偏移量（视图的左上角）
uniform float uZoom;                 // 缩放因子（1.0 = 1个图像像素对应1个屏幕像素）

void main() {
    // aPos 是图像像素坐标 (0..imgW, 0..imgH)
    // 应用缩放和偏移后转换为归一化设备坐标
    vec2 imgPos = aPos - uOffset;    // 相对于视图的图像空间位置
    // 将图像空间映射到屏幕像素：imgPos * uZoom
    vec2 screenPos = imgPos * uZoom;
    // 转换为归一化设备坐标：从 [0, win] 映射到 [-1, +1]
    vec2 ndc = (screenPos / uWinSize) * 2.0 - 1.0;
    // 翻转Y轴，因为OpenGL的NDC Y轴向上，但窗口Y轴向下
    ndc.y = -ndc.y;
    gl_Position = vec4(ndc, 0.0, 1.0);
    vTex = aTex;
}
)glsl";

// 片段着色器源代码 - 用于采样纹理并输出颜色
const char* fragment_shader_src = R"glsl(
#version 330 core
in vec2 vTex;                         // 输入：从顶点着色器传来的纹理坐标
out vec4 FragColor;                   // 输出：片段颜色
uniform sampler2D uTex;               // 纹理采样器
void main() {
    vec4 c = texture(uTex, vTex);     // 从纹理中采样颜色
    FragColor = c;                    // 输出颜色
}
)glsl";

// 文本渲染着色器（用于在像素上显示RGB值）
const char* text_vertex_shader_src = R"glsl(
#version 330 core
layout(location = 0) in vec2 aPos;   // 输入：文本位置
layout(location = 1) in vec2 aTex;   // 输入：纹理坐标
out vec2 vTex;                       // 输出：传递给片段着色器的纹理坐标
uniform vec2 uScreenSize;            // 窗口大小（像素）
uniform vec2 uTextPos;               // 文本在屏幕像素中的位置（左上角为原点）
uniform float uTextScale;            // 文本缩放因子

void main() {
    // 将屏幕像素位置转换为归一化设备坐标
    // uTextPos 是屏幕坐标（左上角为原点，Y轴向下）
    // OpenGL NDC 的Y轴向上，所以需要翻转Y
    vec2 screenPos = (uTextPos + aPos * uTextScale) / uScreenSize * 2.0 - 1.0;
    screenPos.y = -screenPos.y;      // 为OpenGL NDC翻转Y轴（Y轴向上）
    gl_Position = vec4(screenPos, 0.0, 1.0);
    // 翻转纹理Y坐标以修复倒置的文本
    vTex = vec2(aTex.x, 1.0 - aTex.y);
}
)glsl";

// 文本片段着色器源代码
const char* text_fragment_shader_src = R"glsl(
#version 330 core
in vec2 vTex;                        // 输入：纹理坐标
out vec4 FragColor;                  // 输出：片段颜色
uniform sampler2D uTextTex;          // 文本纹理采样器
uniform vec3 uTextColor;             // 文本颜色

void main() {
    // 使用线性过滤以获得更平滑的文本边缘
    float alpha = texture(uTextTex, vTex).r;
    // 应用轻微的抗锯齿以获得更平滑的外观
    alpha = smoothstep(0.3, 0.7, alpha);
    FragColor = vec4(uTextColor, alpha);
}
)glsl";

// 网格渲染着色器（用于绘制像素网格线）
const char* grid_vertex_shader_src = R"glsl(
#version 330 core
layout(location = 0) in vec2 aPos;   // 输入：网格线顶点位置（图像像素坐标）
layout(location = 1) in vec3 aColor; // 输入：顶点颜色
out vec3 vColor;                     // 输出：传递给片段着色器的颜色
uniform vec2 uWinSize;               // 窗口大小
uniform vec2 uImgSize;               // 图像大小
uniform vec2 uOffset;                // 图像坐标偏移
uniform float uZoom;                 // 缩放因子

void main() {
    // 将图像像素坐标转换为归一化设备坐标
    vec2 imgPos = aPos - uOffset;
    vec2 screenPos = imgPos * uZoom;
    vec2 ndc = (screenPos / uWinSize) * 2.0 - 1.0;
    ndc.y = -ndc.y;                  // 翻转Y轴
    gl_Position = vec4(ndc, 0.0, 1.0);
    vColor = aColor;                 // 传递颜色到片段着色器
}
)glsl";

// 网格片段着色器源代码
const char* grid_fragment_shader_src = R"glsl(
#version 330 core
in vec3 vColor;                      // 输入：从顶点着色器传来的颜色
out vec4 FragColor;                  // 输出：片段颜色

void main() {
    FragColor = vec4(vColor, 1.0);
}
)glsl";

// 全局互斥锁用于保护 GLFW 窗口创建（X11 错误处理器需要线程安全）
static std::mutex glfw_window_create_mutex;

// 构造函数：不初始化 GLFW（由 ImageViewer 在主线程中初始化）
ImageViewerOpenGL::ImageViewerOpenGL()
{
    // GLFW 初始化由 ImageViewer 在主线程中完成
    // 这里不做任何初始化
}

// 析构函数：清理所有OpenGL资源和窗口
ImageViewerOpenGL::~ImageViewerOpenGL()
{
    // 销毁所有OpenGL资源（纹理、着色器、缓冲区等）
    destroyGLResources();
    // 销毁GLFW窗口
    if (window_) {
        glfwDestroyWindow(window_);
        window_ = nullptr;
    }
    // 注意：不在这里终止 GLFW，因为可能有其他窗口在使用
    // GLFW 会在程序退出时自动清理
}

// 初始化GLFW窗口和OpenGL上下文
bool ImageViewerOpenGL::initGLFW(const std::string& window_name, bool is_bind_window)
{
    // 设置OpenGL版本为3.3
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    
    // 如果是绑定窗口，禁用窗口大小调整和最大化
    if (is_bind_window) {
        glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
    }

    // 创建GLFW窗口，使用提供的窗口名称
    // 注意：在 X11 环境下，窗口创建需要互斥锁保护，因为错误处理器是全局的
    window_name_ = window_name;
    const char* title = window_name.empty() ? "ImageViewer" : window_name.c_str();
    
    // 使用互斥锁保护窗口创建（避免 X11 错误处理器冲突）
    {
        std::lock_guard<std::mutex> lock(glfw_window_create_mutex);
        window_ = glfwCreateWindow(win_w_, win_h_, title, nullptr, nullptr);
    }
    if (!window_) {
        std::cerr << "错误：创建GLFW窗口失败" << std::endl;
        // 注意：不要在这里调用 glfwTerminate()，因为可能有其他窗口在使用
        return false;
    }
    
    // 如果是绑定窗口，禁用最大化
    if (is_bind_window) {
        glfwSetWindowAttrib(window_, GLFW_RESIZABLE, GLFW_FALSE);
        glfwSetWindowAttrib(window_, GLFW_MAXIMIZED, GLFW_FALSE);
    }
    
    // 设置窗口位置（如果指定了位置）
    if (win_x_ >= 0 && win_y_ >= 0) {
        glfwSetWindowPos(window_, win_x_, win_y_);
    }
    
    // 将当前窗口设置为OpenGL上下文
    glfwMakeContextCurrent(window_);
    glfwSwapInterval(1);  // 启用垂直同步（vsync）

    // 初始化GLEW以加载OpenGL函数
    GLenum err = glewInit();
    if (err != GLEW_OK) {
        std::cerr << "错误：GLEW初始化失败: " << glewGetErrorString(err) << std::endl;
        return false;
    }

    // 设置回调函数
    glfwSetFramebufferSizeCallback(window_, framebufferSizeCallback);   // 窗口大小改变回调
    glfwSetScrollCallback(window_, scrollCallback);                     // 鼠标滚轮回调
    glfwSetMouseButtonCallback(window_, mouseButtonCallback);           // 鼠标按键回调
    glfwSetCursorPosCallback(window_, cursorPosCallback);               // 鼠标移动回调
    glfwSetWindowCloseCallback(window_, windowCloseCallback);           // 窗口关闭回调

    // 将this指针存储到GLFW用户指针中，以便在静态回调函数中访问
    glfwSetWindowUserPointer(window_, this);

    // 启用混合（alpha混合）用于文本和网格渲染
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    return true;
}

// 初始化所有OpenGL资源（着色器、缓冲区、纹理等）
bool ImageViewerOpenGL::initGLResources()
{
    // 编译着色器的辅助lambda函数
    auto compile = [&](GLenum type, const char* src) -> GLuint {
        GLuint s = glCreateShader(type);           // 创建着色器对象
        glShaderSource(s, 1, &src, nullptr);       // 设置着色器源代码
        glCompileShader(s);                        // 编译着色器
        GLint ok = 0;
        glGetShaderiv(s, GL_COMPILE_STATUS, &ok);  // 检查编译状态
        if (!ok) {
            char buf[1024];
            glGetShaderInfoLog(s, sizeof(buf), nullptr, buf);
            std::cerr << "错误：着色器编译失败: " << buf << std::endl;
        }
        return s;
    };

    // 编译主渲染程序的顶点和片段着色器
    GLuint vs = compile(GL_VERTEX_SHADER, vertex_shader_src);
    GLuint fs = compile(GL_FRAGMENT_SHADER, fragment_shader_src);
    program_  = glCreateProgram();                 // 创建着色器程序
    glAttachShader(program_, vs);                  // 附加顶点着色器
    glAttachShader(program_, fs);                  // 附加片段着色器
    glLinkProgram(program_);                       // 链接程序
    GLint ok = 0;
    glGetProgramiv(program_, GL_LINK_STATUS, &ok); // 检查链接状态
    if (!ok) {
        char buf[1024];
        glGetProgramInfoLog(program_, sizeof(buf), nullptr, buf);
        std::cerr << "错误：程序链接失败: " << buf << std::endl;
    }
    glDeleteShader(vs);                            // 删除着色器对象（已链接到程序）
    glDeleteShader(fs);

    // 准备VAO/VBO用于在像素坐标中覆盖整个图像的四边形
    glGenVertexArrays(1, &vao_);                   // 生成顶点数组对象
    glGenBuffers(1, &vbo_);                        // 生成顶点缓冲区对象
    glBindVertexArray(vao_);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_);
    // 稍后更新缓冲区数据（6个顶点，每个顶点4个float：x, y, u, v）
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, nullptr,
                 GL_DYNAMIC_DRAW);
    // 设置顶点属性：位置（vec2）
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void*)0);
    glEnableVertexAttribArray(0);
    // 设置顶点属性：纹理坐标（vec2）
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4,
                          (void*)(sizeof(float) * 2));
    glEnableVertexAttribArray(1);
    glBindVertexArray(0);

    // 创建纹理占位符
    glGenTextures(1, &texture_);
    glBindTexture(GL_TEXTURE_2D, texture_);
    // 默认参数；上传图像时会设置为NEAREST（像素化显示）
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glBindTexture(GL_TEXTURE_2D, 0);

    // 初始化文本渲染器
    initTextRenderer();

    // 初始化网格渲染器
    initGridRenderer();

    return true;
}

// 初始化网格渲染器（用于绘制像素网格线）
void ImageViewerOpenGL::initGridRenderer()
{
    // 编译网格着色器的辅助lambda函数
    auto compile = [&](GLenum type, const char* src) -> GLuint {
        GLuint s = glCreateShader(type);
        glShaderSource(s, 1, &src, nullptr);
        glCompileShader(s);
        GLint ok = 0;
        glGetShaderiv(s, GL_COMPILE_STATUS, &ok);
        if (!ok) {
            char buf[1024];
            glGetShaderInfoLog(s, sizeof(buf), nullptr, buf);
            std::cerr << "错误：网格着色器编译失败: " << buf << std::endl;
        }
        return s;
    };

    // 编译网格渲染程序的顶点和片段着色器
    GLuint vs     = compile(GL_VERTEX_SHADER, grid_vertex_shader_src);
    GLuint fs     = compile(GL_FRAGMENT_SHADER, grid_fragment_shader_src);
    grid_program_ = glCreateProgram();
    glAttachShader(grid_program_, vs);
    glAttachShader(grid_program_, fs);
    glLinkProgram(grid_program_);
    GLint ok = 0;
    glGetProgramiv(grid_program_, GL_LINK_STATUS, &ok);
    if (!ok) {
        char buf[1024];
        glGetProgramInfoLog(grid_program_, sizeof(buf), nullptr, buf);
        std::cerr << "错误：网格程序链接失败: " << buf << std::endl;
    }
    glDeleteShader(vs);
    glDeleteShader(fs);

    // 为网格线创建VAO/VBO（将动态更新）
    // 每个顶点包含：位置(2个float) + 颜色(3个float) = 5个float
    glGenVertexArrays(1, &grid_vao_);
    glGenBuffers(1, &grid_vbo_);
    glBindVertexArray(grid_vao_);
    glBindBuffer(GL_ARRAY_BUFFER, grid_vbo_);
    // 为网格线预留空间（将在renderPixelGrid中更新）
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 5000, nullptr, GL_DYNAMIC_DRAW);
    // 位置属性 (location = 0)
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // 颜色属性 (location = 1)
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(2 * sizeof(float)));
    glEnableVertexAttribArray(1);
    glBindVertexArray(0);
}

// 从OpenCV Mat上传纹理到OpenGL
void ImageViewerOpenGL::uploadTextureFromMat(const cv::Mat& mat)
{
    if (mat.empty())
        return;
    
    // 转换颜色格式：OpenCV使用BGR，OpenGL使用RGB
    cv::Mat rgb;
    if (mat.channels() == 3) {
        cv::cvtColor(mat, rgb, cv::COLOR_BGR2RGB);      // BGR转RGB
    } else if (mat.channels() == 4) {
        cv::cvtColor(mat, rgb, cv::COLOR_BGRA2RGBA);    // BGRA转RGBA
    } else if (mat.channels() == 1) {
        cv::cvtColor(mat, rgb, cv::COLOR_GRAY2RGB);     // 灰度转RGB
    } else {
        rgb = mat.clone();
    }

    // 垂直翻转图像，因为OpenCV原点在左上角，而OpenGL纹理坐标原点在左下角
    cv::Mat flipped;
    cv::flip(rgb, flipped, 0);

    // 绑定纹理并设置参数
    glBindTexture(GL_TEXTURE_2D, texture_);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);             // 设置像素存储对齐方式
    // 使用GL_NEAREST过滤，使缩放时显示像素块（无过滤，保持像素化效果）
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    // 根据通道数确定格式
    GLenum format = GL_RGB;
    if (flipped.channels() == 4)
        format = GL_RGBA;
    // 上传纹理数据到GPU
    glTexImage2D(GL_TEXTURE_2D, 0, format, flipped.cols, flipped.rows, 0, format,
                 GL_UNSIGNED_BYTE, flipped.data);
    glBindTexture(GL_TEXTURE_2D, 0);
}

// 销毁所有OpenGL资源
void ImageViewerOpenGL::destroyGLResources()
{
    // 销毁数字纹理（0-9）
    for (int i = 0; i < 10; i++) {
        if (digit_textures_[i]) {
            glDeleteTextures(1, &digit_textures_[i]);
            digit_textures_[i] = 0;
        }
    }

    // 销毁网格渲染资源
    if (grid_vbo_) {
        glDeleteBuffers(1, &grid_vbo_);
        grid_vbo_ = 0;
    }
    if (grid_vao_) {
        glDeleteVertexArrays(1, &grid_vao_);
        grid_vao_ = 0;
    }
    if (grid_program_) {
        glDeleteProgram(grid_program_);
        grid_program_ = 0;
    }

    // 销毁文本渲染资源
    if (text_vbo_) {
        glDeleteBuffers(1, &text_vbo_);
        text_vbo_ = 0;
    }
    if (text_vao_) {
        glDeleteVertexArrays(1, &text_vao_);
        text_vao_ = 0;
    }
    if (text_program_) {
        glDeleteProgram(text_program_);
        text_program_ = 0;
    }

    // 销毁主纹理
    if (texture_) {
        glDeleteTextures(1, &texture_);
        texture_ = 0;
    }
    // 销毁主渲染缓冲区
    if (vbo_) {
        glDeleteBuffers(1, &vbo_);
        vbo_ = 0;
    }
    if (vao_) {
        glDeleteVertexArrays(1, &vao_);
        vao_ = 0;
    }
    // 销毁主着色器程序
    if (program_) {
        glDeleteProgram(program_);
        program_ = 0;
    }
}

// 显示图像：初始化窗口、设置视图并进入主循环
void ImageViewerOpenGL::showImage(const cv::Mat&     image,
                                  const std::string& window_name)
{
    // 存储图像副本
    original_image_ = image.clone();

    if (original_image_.empty()) {
        std::cerr << "错误：提供的图像为空" << std::endl;
        return;
    }

    // 初始化GLFW窗口和OpenGL上下文
    bool is_bind_window = !bind_name_.empty();
    if (!initGLFW(window_name, is_bind_window))
        return;
    // 初始化所有OpenGL资源（着色器、缓冲区、纹理等）
    if (!initGLResources())
        return;

    // 上传图像纹理到GPU
    uploadTextureFromMat(original_image_);

    // 初始化视图：在窗口中居中显示图像
    // 默认缩放：如果图像大于窗口，则缩放到适合窗口；否则缩放为1.0
    double fitZoomW = (double)win_w_ / original_image_.cols;  // 宽度方向的适合缩放
    double fitZoomH = (double)win_h_ / original_image_.rows;  // 高度方向的适合缩放
    zoom_           = std::min(fitZoomW, fitZoomH);           // 取较小值以完整显示图像
    if (zoom_ > 1.0)
        zoom_ = 1.0;  // 默认不放大；仅在窗口较小时显示大于1像素的尺寸

    // 计算缩放后的图像尺寸
    double scaledImgW = original_image_.cols * zoom_;
    double scaledImgH = original_image_.rows * zoom_;

    // 检查图像在每个维度上是否填满窗口
    bool imageSmallerThanWindowW = (scaledImgW < win_w_);
    bool imageSmallerThanWindowH = (scaledImgH < win_h_);

    // 图像中心在图像坐标中的位置
    double imgCenterX = original_image_.cols * 0.5;
    double imgCenterY = original_image_.rows * 0.5;

    // 窗口中心在屏幕坐标中的位置
    double winCenterX = win_w_ * 0.5;
    double winCenterY = win_h_ * 0.5;

    // 根据图像和窗口的相对大小计算初始偏移量
    if (imageSmallerThanWindowW && imageSmallerThanWindowH) {
        // 图像在两个维度上都小于窗口：居中显示
        offset_x_ = imgCenterX - winCenterX / zoom_;
        offset_y_ = imgCenterY - winCenterY / zoom_;
    } else {
        // 使用原始居中公式
        offset_x_ = (win_w_ - scaledImgW) * 0.5 / zoom_;
        offset_y_ = (win_h_ - scaledImgH) * 0.5 / zoom_;

        // 如果图像在某个维度上未填满窗口，则在该维度上居中
        if (imageSmallerThanWindowW) {
            offset_x_ = imgCenterX - winCenterX / zoom_;
        }
        if (imageSmallerThanWindowH) {
            offset_y_ = imgCenterY - winCenterY / zoom_;
        }

        // 仅在图像填满窗口的维度上进行边界限制
        if (!imageSmallerThanWindowW) {
            if (offset_x_ < 0)
                offset_x_ = 0;
        }
        if (!imageSmallerThanWindowH) {
            if (offset_y_ < 0)
                offset_y_ = 0;
        }
    }

    // 主循环：处理事件并渲染
    while (!glfwWindowShouldClose(window_) && window_) {
        glfwPollEvents();            // 处理窗口事件（鼠标、键盘等）

        // 检查是否应该关闭（通过 window_info_）
        if (window_info_) {
            std::lock_guard<std::mutex> lock(window_info_->mutex);
            if (window_info_->should_close) {
                glfwSetWindowShouldClose(window_, GLFW_TRUE);
            }
        }

        render();                     // 渲染一帧

        glfwSwapBuffers(window_);     // 交换前后缓冲区（双缓冲）
    }

    closeWindow();
}

// 关闭窗口
void ImageViewerOpenGL::closeWindow()
{
    if (window_) {
        glfwSetWindowShouldClose(window_, GLFW_TRUE);
    }
}

// 渲染一帧：绘制图像、网格和像素值
void ImageViewerOpenGL::render()
{
    // 获取当前帧缓冲区大小（处理高DPI显示器）
    int fbw, fbh;
    glfwGetFramebufferSize(window_, &fbw, &fbh);
    win_w_ = fbw;
    win_h_ = fbh;
    glViewport(0, 0, win_w_, win_h_);              // 设置视口
    glClearColor(0.12f, 0.12f, 0.12f, 1.0f);       // 设置清除颜色（深灰色背景）
    glClear(GL_COLOR_BUFFER_BIT);                  // 清除颜色缓冲区

    if (!texture_)
        return;

    // 使用主渲染程序
    glUseProgram(program_);

    // 计算图像像素坐标中的四边形（我们在图像空间中提供位置）
    // 四边形的顶点 (x,y, u,v) 对应图像像素坐标 (0..imgW) 和纹理坐标 (0..1)
    float imgW = (float)original_image_.cols;
    float imgH = (float)original_image_.rows;

    // 顶点：两个三角形覆盖 [0,imgW] x [0,imgH] 区域
    float vertices[6 * 4] = {
        // x, y, u, v
        0.0f, 0.0f, 0.0f, 1.0f, imgW, 0.0f, 1.0f, 1.0f, imgW, imgH, 1.0f, 0.0f,

        0.0f, 0.0f, 0.0f, 1.0f, imgW, imgH, 1.0f, 0.0f, 0.0f, imgH, 0.0f, 0.0f};

    // 更新顶点缓冲区数据
    glBindBuffer(GL_ARRAY_BUFFER, vbo_);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);

    // 设置着色器uniform变量
    GLint locWin  = glGetUniformLocation(program_, "uWinSize");
    GLint locImg  = glGetUniformLocation(program_, "uImgSize");
    GLint locOff  = glGetUniformLocation(program_, "uOffset");
    GLint locZoom = glGetUniformLocation(program_, "uZoom");

    glUniform2f(locWin, (float)win_w_, (float)win_h_);      // 窗口大小
    glUniform2f(locImg, imgW, imgH);                        // 图像大小
    glUniform2f(locOff, (float)offset_x_, (float)offset_y_); // 偏移量
    glUniform1f(locZoom, (float)zoom_);                     // 缩放因子

    // 绑定纹理
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture_);
    GLint locTex = glGetUniformLocation(program_, "uTex");
    glUniform1i(locTex, 0);                                // 设置纹理单元

    // 绘制图像
    glBindVertexArray(vao_);
    glDrawArrays(GL_TRIANGLES, 0, 6);                      // 绘制两个三角形（6个顶点）
    glBindVertexArray(0);

    glBindTexture(GL_TEXTURE_2D, 0);
    glUseProgram(0);

    // 如果缩放足够大，渲染像素网格
    if (zoom_ >= min_zoom_for_grid_) {
        renderPixelGrid();
    }

    // 渲染像素值（renderPixelValues内部会根据像素屏幕大小进行检查）
    // 这确保了无论窗口大小如何，显示都保持一致
    renderPixelValues();
}

// 窗口大小改变回调函数：调整视图以保持图像显示正确
void ImageViewerOpenGL::framebufferSizeCallback(GLFWwindow* win, int w, int h)
{
    ImageViewerOpenGL* th = getThis(win);
    if (!th)
        return;

    // 在更新窗口大小之前，保存图像坐标中的旧中心位置
    double oldCenterX = th->offset_x_ + (double)th->win_w_ * 0.5 / th->zoom_;
    double oldCenterY = th->offset_y_ + (double)th->win_h_ * 0.5 / th->zoom_;

    // 更新窗口大小
    th->win_w_ = w;
    th->win_h_ = h;

    // 计算缩放后的图像尺寸
    double scaledImgW = th->original_image_.cols * th->zoom_;
    double scaledImgH = th->original_image_.rows * th->zoom_;

    // 检查图像在每个维度上是否填满窗口
    bool imageSmallerThanWindowW = (scaledImgW < th->win_w_);
    bool imageSmallerThanWindowH = (scaledImgH < th->win_h_);

    // 图像中心在图像坐标中的位置
    double imgCenterX = th->original_image_.cols * 0.5;
    double imgCenterY = th->original_image_.rows * 0.5;

    // 窗口中心在屏幕坐标中的位置
    double winCenterX = th->win_w_ * 0.5;
    double winCenterY = th->win_h_ * 0.5;

    if (imageSmallerThanWindowW && imageSmallerThanWindowH) {
        // 图像在两个维度上都小于窗口：居中显示
        th->offset_x_ = imgCenterX - winCenterX / th->zoom_;
        th->offset_y_ = imgCenterY - winCenterY / th->zoom_;
    } else {
        // 图像至少在某个维度上大于窗口：保持旧的中心位置
        // 窗口调整大小后恢复中心位置
        th->offset_x_ = oldCenterX - (double)th->win_w_ * 0.5 / th->zoom_;
        th->offset_y_ = oldCenterY - (double)th->win_h_ * 0.5 / th->zoom_;

        // 如果图像在某个维度上未填满窗口，则在该维度上居中
        if (imageSmallerThanWindowW) {
            th->offset_x_ = imgCenterX - winCenterX / th->zoom_;
        }
        if (imageSmallerThanWindowH) {
            th->offset_y_ = imgCenterY - winCenterY / th->zoom_;
        }

        // 仅在图像填满窗口的维度上进行边界限制
        // 在图像小于窗口的维度上不进行限制（已经居中）
        if (!imageSmallerThanWindowW) {
            double maxOx = std::max(0.0, (double)th->original_image_.cols - th->win_w_ / th->zoom_);
            if (th->offset_x_ < 0)
                th->offset_x_ = 0;
            if (th->offset_x_ > maxOx)
                th->offset_x_ = maxOx;
        }
        if (!imageSmallerThanWindowH) {
            double maxOy = std::max(0.0, (double)th->original_image_.rows - th->win_h_ / th->zoom_);
            if (th->offset_y_ < 0)
                th->offset_y_ = 0;
            if (th->offset_y_ > maxOy)
                th->offset_y_ = maxOy;
        }
    }
    
    // 如果是绑定窗口，同步视图状态到绑定组
    if (!th->bind_name_.empty()) {
        th->syncViewStateToBindGroup();
    }
}

// 鼠标滚轮回调函数：实现以鼠标位置为中心的缩放
void ImageViewerOpenGL::scrollCallback(GLFWwindow* win, double xoffset, double yoffset)
{
    ImageViewerOpenGL* th = getThis(win);
    if (!th)
        return;
    // 获取鼠标光标在窗口坐标中的位置
    double mx, my;
    glfwGetCursorPos(win, &mx, &my);

    // 在缩放改变之前，将鼠标位置转换为图像坐标
    double imgX = th->offset_x_ + mx / th->zoom_;
    double imgY = th->offset_y_ + my / th->zoom_;

    // 每个滚轮步的缩放因子（向上滚动放大1.1倍，向下滚动缩小0.9倍）
    double factor = (yoffset > 0) ? 1.1 : 0.9;

    double new_zoom = th->zoom_ * factor;

    // 应用最小缩放限制
    if (new_zoom < 0.01)
        new_zoom = 0.01;

    // 应用最大缩放限制：仅在放大时（factor > 1.0）
    // 最大缩放设置为100.0（允许放大到100倍）
    double max_zoom_limit = 100.0;
    if (factor > 1.0) {  // 仅在放大时
        if (new_zoom > max_zoom_limit)
            new_zoom = max_zoom_limit;  // 限制在100倍缩放
    }

    th->zoom_ = new_zoom;

    // 计算缩放后的图像尺寸
    double scaledImgW = th->original_image_.cols * th->zoom_;
    double scaledImgH = th->original_image_.rows * th->zoom_;

    // 检查图像在每个维度上是否填满窗口
    bool imageSmallerThanWindowW = (scaledImgW < th->win_w_);
    bool imageSmallerThanWindowH = (scaledImgH < th->win_h_);

    // 图像中心在图像坐标中的位置
    double imgCenterX = th->original_image_.cols * 0.5;
    double imgCenterY = th->original_image_.rows * 0.5;

    // 窗口中心在屏幕坐标中的位置
    double winCenterX = th->win_w_ * 0.5;
    double winCenterY = th->win_h_ * 0.5;

    if (imageSmallerThanWindowW && imageSmallerThanWindowH) {
        // 图像在两个维度上都小于窗口：居中显示
        th->offset_x_ = imgCenterX - winCenterX / th->zoom_;
        th->offset_y_ = imgCenterY - winCenterY / th->zoom_;
    } else {
        // 图像至少在某个维度上大于窗口：保持鼠标位置固定，但在图像未填满的地方居中
        // 缩放后，调整偏移量，使imgX/imgY保持在相同的屏幕位置
        th->offset_x_ = imgX - mx / th->zoom_;
        th->offset_y_ = imgY - my / th->zoom_;

        // 如果图像在某个维度上未填满窗口，则在该维度上居中
        if (imageSmallerThanWindowW) {
            th->offset_x_ = imgCenterX - winCenterX / th->zoom_;
        }
        if (imageSmallerThanWindowH) {
            th->offset_y_ = imgCenterY - winCenterY / th->zoom_;
        }

        // 仅在图像填满窗口的维度上将偏移量限制到图像边界
        // 在图像小于窗口的维度上不进行限制（已经居中）
        if (!imageSmallerThanWindowW) {
            double maxOx = std::max(0.0, (double)th->original_image_.cols - th->win_w_ / th->zoom_);
            if (th->offset_x_ < 0)
                th->offset_x_ = 0;
            if (th->offset_x_ > maxOx)
                th->offset_x_ = maxOx;
        }
        if (!imageSmallerThanWindowH) {
            double maxOy = std::max(0.0, (double)th->original_image_.rows - th->win_h_ / th->zoom_);
            if (th->offset_y_ < 0)
                th->offset_y_ = 0;
            if (th->offset_y_ > maxOy)
                th->offset_y_ = maxOy;
        }
    }
    
    // 如果是绑定窗口，同步视图状态到绑定组
    if (!th->bind_name_.empty()) {
        th->syncViewStateToBindGroup();
    }
}

// 鼠标按键回调函数：处理拖拽开始和结束
void ImageViewerOpenGL::mouseButtonCallback(GLFWwindow* win, int button, int action, int mods)
{
    ImageViewerOpenGL* th = getThis(win);
    if (!th)
        return;
    if (button == GLFW_MOUSE_BUTTON_LEFT) {
        if (action == GLFW_PRESS) {
            // 开始拖拽：记录鼠标位置
            th->dragging_ = true;
            glfwGetCursorPos(win, &th->last_mouse_x_, &th->last_mouse_y_);
        } else if (action == GLFW_RELEASE) {
            // 在结束拖拽前，获取当前鼠标位置并更新 last_mouse_x_ 和 last_mouse_y_
            // 这样可以避免下次拖动开始时计算出异常的增量
            double current_mouse_x, current_mouse_y;
            glfwGetCursorPos(win, &current_mouse_x, &current_mouse_y);
            th->last_mouse_x_ = current_mouse_x;
            th->last_mouse_y_ = current_mouse_y;
            
            // 结束拖拽
            th->dragging_ = false;
            
            // 拖拽结束后，如果图像未填满窗口，则居中显示
            double scaledImgW = th->original_image_.cols * th->zoom_;
            double scaledImgH = th->original_image_.rows * th->zoom_;
            bool imageSmallerThanWindowW = (scaledImgW < th->win_w_);
            bool imageSmallerThanWindowH = (scaledImgH < th->win_h_);
            
            if (imageSmallerThanWindowW || imageSmallerThanWindowH) {
                double imgCenterX = th->original_image_.cols * 0.5;
                double imgCenterY = th->original_image_.rows * 0.5;
                double winCenterX = th->win_w_ * 0.5;
                double winCenterY = th->win_h_ * 0.5;
                
                if (imageSmallerThanWindowW) {
                    th->offset_x_ = imgCenterX - winCenterX / th->zoom_;
                }
                if (imageSmallerThanWindowH) {
                    th->offset_y_ = imgCenterY - winCenterY / th->zoom_;
                }
            }
            
            // 拖动结束时，如果是绑定窗口，总是同步一次视图状态到绑定组
            // 这样可以确保所有绑定窗口的状态一致，即使图像填满窗口也需要同步
            if (!th->bind_name_.empty()) {
                th->syncViewStateToBindGroup();
            }
        }
    }
}

// 鼠标移动回调函数：处理图像拖拽
void ImageViewerOpenGL::cursorPosCallback(GLFWwindow* win, double xpos, double ypos)
{
    ImageViewerOpenGL* th = getThis(win);
    if (!th)
        return;
    if (th->dragging_) {
        // 检查 last_mouse_x_ 和 last_mouse_y_ 是否在合理范围内
        // 如果不在窗口范围内（允许一些边界误差），说明可能未正确初始化，重新初始化
        const double MARGIN = 50.0;  // 允许50像素的边界误差
        if (th->last_mouse_x_ < -MARGIN || th->last_mouse_x_ > th->win_w_ + MARGIN ||
            th->last_mouse_y_ < -MARGIN || th->last_mouse_y_ > th->win_h_ + MARGIN) {
            th->last_mouse_x_ = xpos;
            th->last_mouse_y_ = ypos;
            return;  // 跳过本次更新，等待下一次正常的拖动
        }
        
        // 计算鼠标移动的增量
        double dx = xpos - th->last_mouse_x_;
        double dy = ypos - th->last_mouse_y_;
        
        // 检查增量是否异常大（可能是 last_mouse_x_/last_mouse_y_ 未正确初始化）
        // 使用更小的阈值（100像素），因为正常的鼠标移动增量通常不会超过这个值
        // 如果增量超过100像素，说明可能是初始化问题，重新初始化并跳过本次更新
        const double MAX_NORMAL_DELTA = 100.0;
        if (std::abs(dx) > MAX_NORMAL_DELTA || std::abs(dy) > MAX_NORMAL_DELTA) {
            th->last_mouse_x_ = xpos;
            th->last_mouse_y_ = ypos;
            return;  // 跳过本次更新，等待下一次正常的拖动
        }

        // 在拖拽过程中，直接更新偏移量，不进行任何边界限制
        // 这样可以确保拖拽过程平滑，避免跳动
        th->offset_x_ -= dx / th->zoom_;
        th->offset_y_ -= dy / th->zoom_;

        // 计算缩放后的图像尺寸
        double scaledImgW = th->original_image_.cols * th->zoom_;
        double scaledImgH = th->original_image_.rows * th->zoom_;

        // 检查图像在每个维度上是否填满窗口
        bool imageSmallerThanWindowW = (scaledImgW < th->win_w_);
        bool imageSmallerThanWindowH = (scaledImgH < th->win_h_);

        // 仅在图像填满窗口的维度上进行边界限制
        // 在拖拽过程中，如果图像未填满窗口，不强制居中，允许自由拖拽
        if (!imageSmallerThanWindowW) {
            double maxOx = std::max(0.0, (double)th->original_image_.cols - th->win_w_ / th->zoom_);
            if (th->offset_x_ < 0)
                th->offset_x_ = 0;
            if (th->offset_x_ > maxOx)
                th->offset_x_ = maxOx;
        }
        // 注意：在拖拽过程中，如果图像未填满窗口，不强制居中，避免跳动
        
        if (!imageSmallerThanWindowH) {
            double maxOy = std::max(0.0, (double)th->original_image_.rows - th->win_h_ / th->zoom_);
            if (th->offset_y_ < 0)
                th->offset_y_ = 0;
            if (th->offset_y_ > maxOy)
                th->offset_y_ = maxOy;
        }
        // 注意：在拖拽过程中，如果图像未填满窗口，不强制居中，避免跳动

        // 更新上次鼠标位置
        th->last_mouse_x_ = xpos;
        th->last_mouse_y_ = ypos;
        
        // 在拖动过程中，如果是绑定窗口，同步视图状态到绑定组
        // 这样可以实现实时同步，其他窗口会跟随当前窗口一起移动
        if (!th->bind_name_.empty()) {
            th->syncViewStateToBindGroup();
        }
    }
}

// 将this指针附加到窗口（用于在静态回调中访问实例）
void ImageViewerOpenGL::attachToWindow()
{
    if (window_)
        glfwSetWindowUserPointer(window_, this);
}

// 从GLFW窗口获取ImageViewerOpenGL实例指针
ImageViewerOpenGL* ImageViewerOpenGL::getThis(GLFWwindow* win)
{
    if (!win)
        return nullptr;
    return reinterpret_cast<ImageViewerOpenGL*>(glfwGetWindowUserPointer(win));
}

// 窗口关闭回调：当用户点击关闭按钮时调用
void ImageViewerOpenGL::windowCloseCallback(GLFWwindow* win)
{
    ImageViewerOpenGL* th = getThis(win);
    if (!th || !th->window_info_)
        return;
    
    // 标记窗口应该关闭（GLFW 已经设置了 glfwWindowShouldClose）
    // 主循环会自然退出，线程结束后标记为 finished
    // 窗口信息会在下次调用 destroyDisplay 或 destroyAllDisplay 时清理
    WindowInfo* win_info = th->window_info_;
    if (win_info) {
        std::lock_guard<std::mutex> lock(win_info->mutex);
        win_info->should_close = true;
        
        // 如果是绑定窗口，从绑定组中移除
        if (!win_info->bind_name.empty() && win_info->parent_viewer) {
            // 注意：这里不能直接操作 bind_groups_，因为需要 windows_mutex_ 锁
            // 这个操作会在 destroyBindImage 或 destroyAllDisplay 中处理
        }
    }
}

// ==================== 公共包装类，匹配用户的原始类接口 ====================

// 静态成员变量定义
std::mutex ImageViewer::glfw_init_mutex_;
bool       ImageViewer::glfw_initialized_ = false;

// 确保 GLFW 在主线程中初始化
void ImageViewer::ensureGLFWInitialized()
{
    std::lock_guard<std::mutex> lock(glfw_init_mutex_);
    if (!glfw_initialized_) {
        if (!glfwInit()) {
            std::cerr << "错误：GLFW初始化失败" << std::endl;
        } else {
            glfw_initialized_ = true;
        }
    }
}

ImageViewer::ImageViewer()
{
    // 在主线程中初始化 GLFW（GLFW 要求在主线程初始化）
    ensureGLFWInitialized();
}

ImageViewer::~ImageViewer()
{
    // 析构时销毁所有窗口
    destroyAllDisplay();
}

// 显示线程函数：在独立线程中运行图像显示
void ImageViewer::runDisplayThread(WindowInfo* win_info, const cv::Mat& image, const std::string& window_name)
{
    if (!win_info) {
        return;
    }

    // 确保 GLFW 已初始化（虽然应该在主线程中初始化，但这里作为保险）
    ensureGLFWInitialized();

    // 创建查看器实例
    win_info->viewer = std::make_unique<ImageViewerOpenGL>();
    
    // 设置窗口信息指针（用于关闭回调）
    win_info->viewer->window_info_ = win_info;
    
    // 设置绑定名称
    win_info->viewer->bind_name_ = win_info->bind_name;
    
    // 在显示线程中运行显示循环
    win_info->viewer->showImage(image, window_name);
    
    // 显示循环结束后，标记线程已结束
    // 注意：不要在这里删除 WindowInfo，因为 window_info_ 指针可能还在使用
    // 让主线程通过 destroyDisplay 或 destroyAllDisplay 来清理
    {
        std::lock_guard<std::mutex> lock(win_info->mutex);
        win_info->thread_finished = true;
    }
    
    // 清空 viewer 指针和 window_info_ 指针，避免悬空引用
    if (win_info->viewer) {
        win_info->viewer->window_info_ = nullptr;
    }
    win_info->viewer.reset();
}

// 显示图像：在独立线程中创建OpenGL查看器实例并显示
void ImageViewer::showImage(const cv::Mat&     image,
                            const std::string& window_name)
{
    if (image.empty()) {
        std::cerr << "错误：尝试显示空图像" << std::endl;
        return;
    }

    std::lock_guard<std::mutex> lock(windows_mutex_);

    // 如果窗口已存在，先销毁它
    auto it = windows_.find(window_name);
    if (it != windows_.end()) {
        // 等待旧线程结束
        if (it->second->thread && it->second->thread->joinable()) {
            // 标记窗口应该关闭
            {
                std::lock_guard<std::mutex> win_lock(it->second->mutex);
                it->second->should_close = true;
            }
            // 通知查看器关闭窗口
            if (it->second->viewer) {
                it->second->viewer->closeWindow();
            }
            // 等待线程结束
            it->second->thread->join();
        }
        // 从绑定组中移除（如果存在）
        if (!it->second->bind_name.empty()) {
            auto bind_it = bind_groups_.find(it->second->bind_name);
            if (bind_it != bind_groups_.end()) {
                auto& group = bind_it->second;
                group.erase(std::remove(group.begin(), group.end(), window_name), group.end());
                if (group.empty()) {
                    bind_groups_.erase(bind_it);
                }
            }
        }
        windows_.erase(it);
    }

    // 创建新的窗口信息
    auto win_info = std::make_unique<WindowInfo>();
    win_info->should_close = false;
    win_info->thread_finished = false;
    win_info->parent_viewer = this;
    win_info->window_name = window_name;
    win_info->bind_name = "";  // 非绑定窗口
    win_info->image_size = image.size();  // 存储图像尺寸
    
    // 复制图像数据（因为线程会异步使用）
    cv::Mat image_copy = image.clone();
    
    // 创建并启动显示线程
    win_info->thread = std::make_unique<std::thread>(
        runDisplayThread, win_info.get(), image_copy, window_name
    );
    
    // 将窗口信息存储到映射中
    windows_[window_name] = std::move(win_info);
}

// 显示绑定图像窗口
void ImageViewer::showBindImage(const cv::Mat& image, const std::string& window_name, const std::string& bind_name)
{
    if (image.empty()) {
        std::cerr << "错误：尝试显示空图像" << std::endl;
        return;
    }
    
    if (bind_name.empty()) {
        std::cerr << "错误：bind_name 不能为空" << std::endl;
        return;
    }

    // 在窗口名称尾部添加 " (bind)" 来区分绑定窗口
    std::string bind_window_name = window_name + " (bind)";

    std::lock_guard<std::mutex> lock(windows_mutex_);

    // 检查绑定组中是否已有窗口，如果有，检查图像尺寸是否一致
    auto bind_it = bind_groups_.find(bind_name);
    if (bind_it != bind_groups_.end() && !bind_it->second.empty()) {
        // 获取绑定组中第一个窗口的图像尺寸作为参考
        std::string ref_window_name = bind_it->second[0];
        auto ref_it = windows_.find(ref_window_name);
        if (ref_it != windows_.end()) {
            // 优先使用 WindowInfo 中存储的图像尺寸（在创建时设置）
            cv::Size ref_size = ref_it->second->image_size;
            // 如果 WindowInfo 中的尺寸无效，尝试从 viewer 获取（向后兼容）
            if (ref_size.width == 0 && ref_size.height == 0 && ref_it->second->viewer) {
                ref_size = ref_it->second->viewer->original_image_.size();
            }
            if (ref_size.width > 0 && ref_size.height > 0 && image.size() != ref_size) {
                std::cerr << "错误：绑定窗口的图像尺寸必须相同。期望尺寸: " 
                          << ref_size.width << "x" << ref_size.height 
                          << ", 实际尺寸: " << image.cols << "x" << image.rows << std::endl;
                return;
            }
        }
    }

    // 如果窗口已存在，先销毁它
    auto it = windows_.find(bind_window_name);
    if (it != windows_.end()) {
        // 等待旧线程结束
        if (it->second->thread && it->second->thread->joinable()) {
            // 标记窗口应该关闭
            {
                std::lock_guard<std::mutex> win_lock(it->second->mutex);
                it->second->should_close = true;
            }
            // 通知查看器关闭窗口
            if (it->second->viewer) {
                it->second->viewer->closeWindow();
            }
            // 等待线程结束
            it->second->thread->join();
        }
        // 从旧的绑定组中移除（如果存在）
        if (!it->second->bind_name.empty() && it->second->bind_name != bind_name) {
            auto old_bind_it = bind_groups_.find(it->second->bind_name);
            if (old_bind_it != bind_groups_.end()) {
                auto& old_group = old_bind_it->second;
                old_group.erase(std::remove(old_group.begin(), old_group.end(), bind_window_name), old_group.end());
                if (old_group.empty()) {
                    bind_groups_.erase(old_bind_it);
                }
            }
        }
        windows_.erase(it);
    }

    // 创建新的窗口信息
    auto win_info = std::make_unique<WindowInfo>();
    win_info->should_close = false;
    win_info->thread_finished = false;
    win_info->parent_viewer = this;
    win_info->window_name = bind_window_name;  // 使用添加了 " (bind)" 的窗口名称
    win_info->bind_name = bind_name;
    win_info->image_size = image.size();  // 存储图像尺寸，用于后续的尺寸检查
    
    // 复制图像数据（因为线程会异步使用）
    cv::Mat image_copy = image.clone();
    
    // 创建并启动显示线程
    win_info->thread = std::make_unique<std::thread>(
        runDisplayThread, win_info.get(), image_copy, bind_window_name
    );
    
    // 将窗口信息存储到映射中
    windows_[bind_window_name] = std::move(win_info);
    
    // 添加到绑定组
    bind_groups_[bind_name].push_back(bind_window_name);
}

void ImageViewer::closeWindow()
{
    // 保持向后兼容，但不做任何操作
    // 使用 destroyAllDisplay() 或 destroyDisplay() 来关闭窗口
}

// 等待用户输入回车后继续
void ImageViewer::waitDisplay()
{
    std::cout << "按回车键继续..." << std::endl;
    std::cin.get();
}

// 从映射中移除窗口（线程安全）
// 注意：只有在确认线程已结束或可以安全删除时才调用此函数
void ImageViewer::removeWindow(const std::string& window_name)
{
    std::unique_lock<std::mutex> lock(windows_mutex_);
    auto it = windows_.find(window_name);
    if (it != windows_.end()) {
        // 检查线程是否已结束
        bool finished = false;
        std::thread* thread_ptr = nullptr;
        {
            std::lock_guard<std::mutex> win_lock(it->second->mutex);
            finished = it->second->thread_finished;
            it->second->should_close = true;
            thread_ptr = it->second->thread.get();
        }
        
        // 如果线程已结束，可以安全删除
        if (finished) {
            // 确保线程已 join（如果还未 join）
            if (thread_ptr && thread_ptr->joinable()) {
                // 释放锁，避免死锁（join 可能需要一些时间）
                lock.unlock();
                thread_ptr->join();
                lock.lock();
                // 重新查找，因为锁释放期间可能被修改
                it = windows_.find(window_name);
                if (it == windows_.end()) {
                    return;  // 已经被其他线程删除
                }
            }
            // 从映射中移除
            windows_.erase(it);
        }
        // 如果线程未结束，只标记关闭，不删除（等待线程自然结束）
    }
}

// 销毁指定窗口
void ImageViewer::destroyDisplay(const std::string& window_name)
{
    std::unique_lock<std::mutex> lock(windows_mutex_);
    
    auto it = windows_.find(window_name);
    if (it != windows_.end()) {
        // 移动 WindowInfo 到局部变量，确保在 join 期间不会被销毁
        auto win_info = std::move(it->second);
        
        // 从映射中移除（在 join 之前）
        windows_.erase(it);
        
        // 标记窗口应该关闭
        {
            std::lock_guard<std::mutex> win_lock(win_info->mutex);
            win_info->should_close = true;
        }
        
        // 通知查看器关闭窗口（如果还存在）
        // 注意：如果窗口已经被手动关闭，viewer 可能已经是 nullptr
        if (win_info->viewer) {
            // 检查 window_info_ 是否仍然有效
            if (win_info->viewer->window_info_ == win_info.get()) {
                win_info->viewer->closeWindow();
            }
        }
        
        // 移动 thread 对象到局部变量
        // 注意：即使线程已经 finished，如果它仍然是 joinable 的，我们也必须移动它
        // 否则在 win_info 析构时，thread 的析构函数会调用 std::terminate()
        std::thread thread_to_join;
        if (win_info->thread && win_info->thread->joinable()) {
            // 移动 thread 对象，无论线程是否已经 finished
            // 只要它是 joinable 的，就必须移动它
            thread_to_join = std::move(*win_info->thread);
        }
        
        // 释放锁，避免死锁
        lock.unlock();
        
        // join 线程（如果存在）
        // 即使线程已经 finished，如果它仍然是 joinable 的，我们也需要 join 它
        if (thread_to_join.joinable()) {
            thread_to_join.join();
        }
        
        // win_info 在函数结束时自动销毁，此时线程已 join
    }
}

// 销毁所有窗口（包括绑定和非绑定窗口）
void ImageViewer::destroyAllDisplay()
{
    std::unique_lock<std::mutex> lock(windows_mutex_);
    
    if (windows_.empty()) {
        // 清空绑定组映射
        bind_groups_.clear();
        return;
    }
    
    // 先收集所有需要关闭的窗口信息和线程对象
    // 注意：我们需要保存 thread 对象的移动引用，而不是指针
    std::vector<std::unique_ptr<WindowInfo>> windows_to_cleanup;
    std::vector<std::thread> threads_to_join;
    
    for (auto& pair : windows_) {
        // 检查窗口信息是否有效
        if (!pair.second) {
            continue;
        }
        
        // 检查窗口是否已经关闭（通过检查 viewer 是否为空或窗口是否应该关闭）
        bool already_closed = false;
        {
            std::lock_guard<std::mutex> win_lock(pair.second->mutex);
            if (pair.second->thread_finished || !pair.second->viewer) {
                already_closed = true;
            }
        }
        
        if (already_closed) {
            // 窗口已经关闭，直接清理
            if (pair.second->thread && pair.second->thread->joinable()) {
                threads_to_join.push_back(std::move(*pair.second->thread));
            }
            windows_to_cleanup.push_back(std::move(pair.second));
            continue;
        }
        
        // 标记窗口应该关闭
        {
            std::lock_guard<std::mutex> win_lock(pair.second->mutex);
            pair.second->should_close = true;
        }
        
        // 通知查看器关闭窗口（如果还存在）
        // 注意：如果窗口已经被手动关闭，viewer 可能已经是 nullptr
        if (pair.second->viewer) {
            // 检查 window_info_ 是否仍然有效
            if (pair.second->viewer->window_info_ == pair.second.get()) {
                pair.second->viewer->closeWindow();
            }
        }
        
        // 收集所有 joinable 的线程（移动 thread 对象，确保它不会被销毁）
        // 注意：即使线程已经 finished，如果它仍然是 joinable 的，我们也必须处理它
        // 否则在 WindowInfo 析构时，thread 的析构函数会调用 std::terminate()
        if (pair.second->thread && pair.second->thread->joinable()) {
            // 移动 thread 对象到 vector，确保它在 join 期间不会被销毁
            // 无论线程是否已经 finished，只要它是 joinable 的，就必须移动它
            threads_to_join.push_back(std::move(*pair.second->thread));
        }
        
        // 移动 WindowInfo 到清理列表，确保它在 join 期间不会被销毁
        windows_to_cleanup.push_back(std::move(pair.second));
    }
    
    // 清空映射和绑定组（此时所有 WindowInfo 都已移动到 windows_to_cleanup）
    windows_.clear();
    bind_groups_.clear();
    
    // 释放锁，join 所有线程
    lock.unlock();
    
    // 给线程一些时间退出（GLFW 需要处理关闭事件）
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    
    // 处理所有线程：join 或 detach
    for (auto& thread : threads_to_join) {
        if (thread.joinable()) {
            // 使用超时机制，避免无限等待
            // 如果线程在 3 秒内没有退出，就 detach 它
            auto future = std::async(std::launch::async, [&thread]() {
                if (thread.joinable()) {
                    thread.join();
                }
            });
            
            if (future.wait_for(std::chrono::seconds(3)) == std::future_status::timeout) {
                // 超时，detach 线程（让它自己结束）
                std::cerr << "警告：线程未能在 3 秒内退出，将 detach" << std::endl;
                if (thread.joinable()) {
                    thread.detach();
                }
                future.wait();  // 等待 async 任务完成
            } else {
                // 正常退出，等待完成
                future.wait();
            }
        }
    }
    
    // 确保所有线程都已被处理（join 或 detach）
    // 现在可以安全地销毁 windows_to_cleanup
    // windows_to_cleanup 在函数结束时自动销毁，此时所有 thread 对象都已被处理
}

// 销毁所有拥有相同 bind_name 的窗口
void ImageViewer::destroyBindImage(const std::string& bind_name)
{
    if (bind_name.empty()) {
        return;
    }
    
    std::unique_lock<std::mutex> lock(windows_mutex_);
    
    // 查找绑定组
    auto bind_it = bind_groups_.find(bind_name);
    if (bind_it == bind_groups_.end()) {
        return;  // 绑定组不存在
    }
    
    // 收集需要关闭的窗口信息和线程对象
    std::vector<std::unique_ptr<WindowInfo>> windows_to_cleanup;
    std::vector<std::thread> threads_to_join;
    std::vector<std::string> windows_to_remove;
    
    for (const std::string& window_name : bind_it->second) {
        auto win_it = windows_.find(window_name);
        if (win_it == windows_.end()) {
            continue;  // 窗口已经不存在（可能已手动关闭）
        }
        
        // 检查窗口是否已经关闭
        bool already_closed = false;
        {
            std::lock_guard<std::mutex> win_lock(win_it->second->mutex);
            if (win_it->second->thread_finished || !win_it->second->viewer) {
                already_closed = true;
            }
        }
        
        if (already_closed) {
            // 窗口已经关闭，直接清理
            if (win_it->second->thread && win_it->second->thread->joinable()) {
                threads_to_join.push_back(std::move(*win_it->second->thread));
            }
            windows_to_cleanup.push_back(std::move(win_it->second));
            windows_to_remove.push_back(window_name);
            continue;
        }
        
        // 标记窗口应该关闭
        {
            std::lock_guard<std::mutex> win_lock(win_it->second->mutex);
            win_it->second->should_close = true;
        }
        
        // 通知查看器关闭窗口（如果还存在）
        if (win_it->second->viewer) {
            if (win_it->second->viewer->window_info_ == win_it->second.get()) {
                win_it->second->viewer->closeWindow();
            }
        }
        
        // 收集线程对象
        if (win_it->second->thread && win_it->second->thread->joinable()) {
            threads_to_join.push_back(std::move(*win_it->second->thread));
        }
        
        // 移动 WindowInfo 到清理列表
        windows_to_cleanup.push_back(std::move(win_it->second));
        windows_to_remove.push_back(window_name);
    }
    
    // 从映射中移除窗口
    for (const std::string& window_name : windows_to_remove) {
        windows_.erase(window_name);
    }
    
    // 从绑定组中移除
    bind_groups_.erase(bind_it);
    
    // 释放锁，join 所有线程
    lock.unlock();
    
    // 给线程一些时间退出
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    
    // 处理所有线程
    for (auto& thread : threads_to_join) {
        if (thread.joinable()) {
            auto future = std::async(std::launch::async, [&thread]() {
                if (thread.joinable()) {
                    thread.join();
                }
            });
            
            if (future.wait_for(std::chrono::seconds(3)) == std::future_status::timeout) {
                std::cerr << "警告：线程未能在 3 秒内退出，将 detach" << std::endl;
                if (thread.joinable()) {
                    thread.detach();
                }
                future.wait();
            } else {
                future.wait();
            }
        }
    }
}

// ============= 文本渲染实现 =============

// 创建数字纹理：生成8x8像素的数字位图
cv::Mat ImageViewerOpenGL::createDigitTexture(char digit)
{
    // 创建8x8位图，采用类似San Francisco字体的设计风格
    cv::Mat texture(8, 8, CV_8UC1, cv::Scalar(0));

    // 7段式（数码管）风格的数字图案（8x8）
    // 特点：长垂直段、窄宽度、数码显示外观
    static const unsigned char digit_patterns[10][8] = {
        // 0 - segments: top, upper-left, lower-left, lower-right, upper-right, bottom
        {0b00111100, 0b01000010, 0b01000010, 0b01000010, 0b01000010, 0b01000010, 0b01000010, 0b00111100},
        // 1 - segments: upper-right, lower-right (long and thin)
        {0b00001000, 0b00011000, 0b00001000, 0b00001000, 0b00001000, 0b00001000, 0b00001000, 0b00011100},
        // 2 - segments: top, upper-right, middle, lower-left, bottom
        {0b00111100, 0b01000010, 0b00000010, 0b00000100, 0b00011000, 0b00100000, 0b01000000, 0b01111110},
        // 3 - segments: top, upper-right, middle, lower-right, bottom
        {0b00111100, 0b01000010, 0b00000010, 0b00011100, 0b00000110, 0b00000010, 0b01000010, 0b00111100},
        // 4 - segments: upper-left, upper-right, middle, lower-right
        {0b00000100, 0b00001100, 0b00010100, 0b00100100, 0b01000100, 0b01111111, 0b00000100, 0b00000100},
        // 5 - segments: top, upper-left, middle, lower-right, bottom
        {0b00111110, 0b00100000, 0b00100000, 0b00111100, 0b00000010, 0b00000010, 0b00100010, 0b00011100},
        // 6 - segments: top, upper-left, middle, lower-left, lower-right, bottom
        {0b00111100, 0b01000010, 0b01000000, 0b01111100, 0b01000010, 0b01000010, 0b01000010, 0b00111100},
        // 7 - segments: top, upper-right, lower-right
        {0b01111110, 0b00000010, 0b00000100, 0b00001000, 0b00001000, 0b00010000, 0b00010000, 0b00010000},
        // 8 - segments: all segments (full 8-like)
        {0b00111100, 0b01000010, 0b01000010, 0b00111100, 0b01000010, 0b01000010, 0b01000010, 0b00111100},
        // 9 - segments: top, upper-left, upper-right, middle, lower-right, bottom
        {0b00111100, 0b01000010, 0b01000010, 0b01000010, 0b00111110, 0b00000010, 0b01000010, 0b00111100}};

    if (digit >= '0' && digit <= '9') {
        int idx = digit - '0';
        for (int y = 0; y < 8; y++) {
            unsigned char row = digit_patterns[idx][y];
            for (int x = 0; x < 8; x++) {
                texture.at<uchar>(y, x) = (row & (1 << (7 - x))) ? 255 : 0;
            }
        }
    }

    return texture;
}

// 初始化文本渲染器：创建数字纹理、编译着色器、设置缓冲区
void ImageViewerOpenGL::initTextRenderer()
{
    // 初始化数字纹理为0
    for (int i = 0; i < 10; i++) {
        digit_textures_[i] = 0;
    }

    // 为数字0-9创建纹理
    for (int i = 0; i < 10; i++) {
        cv::Mat digit_img = createDigitTexture('0' + i);
        glGenTextures(1, &digit_textures_[i]);
        glBindTexture(GL_TEXTURE_2D, digit_textures_[i]);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        // 使用线性过滤以获得更平滑的文本渲染
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 8, 8, 0, GL_RED, GL_UNSIGNED_BYTE, digit_img.data);
    }
    glBindTexture(GL_TEXTURE_2D, 0);

    // 编译文本着色器的辅助lambda函数
    auto compile = [&](GLenum type, const char* src) -> GLuint {
        GLuint s = glCreateShader(type);
        glShaderSource(s, 1, &src, nullptr);
        glCompileShader(s);
        GLint ok = 0;
        glGetShaderiv(s, GL_COMPILE_STATUS, &ok);
        if (!ok) {
            char buf[1024];
            glGetShaderInfoLog(s, sizeof(buf), nullptr, buf);
            std::cerr << "错误：文本着色器编译失败: " << buf << std::endl;
        }
        return s;
    };

    // 编译文本渲染程序的顶点和片段着色器
    GLuint vs     = compile(GL_VERTEX_SHADER, text_vertex_shader_src);
    GLuint fs     = compile(GL_FRAGMENT_SHADER, text_fragment_shader_src);
    text_program_ = glCreateProgram();
    glAttachShader(text_program_, vs);
    glAttachShader(text_program_, fs);
    glLinkProgram(text_program_);
    GLint ok = 0;
    glGetProgramiv(text_program_, GL_LINK_STATUS, &ok);
    if (!ok) {
        char buf[1024];
        glGetProgramInfoLog(text_program_, sizeof(buf), nullptr, buf);
        std::cerr << "错误：文本程序链接失败: " << buf << std::endl;
        text_program_ = 0;  // 标记为失败
    }

    glDeleteShader(vs);
    glDeleteShader(fs);

    // 为文本渲染创建VAO/VBO（四边形）
    glGenVertexArrays(1, &text_vao_);
    glGenBuffers(1, &text_vbo_);
    glBindVertexArray(text_vao_);
    glBindBuffer(GL_ARRAY_BUFFER, text_vbo_);

    // 文本的四边形顶点（8x8字符）
    float quad[] = {
        0.0f, 0.0f, 0.0f, 1.0f,  // 左下
        8.0f, 0.0f, 1.0f, 1.0f,  // 右下
        8.0f, 8.0f, 1.0f, 0.0f,  // 右上
        0.0f, 0.0f, 0.0f, 1.0f,  // 左下
        8.0f, 8.0f, 1.0f, 0.0f,  // 右上
        0.0f, 8.0f, 0.0f, 0.0f   // 左上
    };

    glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
    glEnableVertexAttribArray(1);
    glBindVertexArray(0);
}

// 在屏幕位置绘制文本
void ImageViewerOpenGL::drawTextAtScreenPos(float x, float y, const std::string& text, float scale, float r, float g, float b)
{
    if (!text_program_) {
        std::cerr << "错误：drawTextAtScreenPos: text_program_ 为空！" << std::endl;
        return;
    }
    if (text.empty())
        return;

    // 确保文本在图像上方 - 如果启用了深度测试则禁用它
    glDisable(GL_DEPTH_TEST);

    // 使用文本渲染程序并绑定VAO
    glUseProgram(text_program_);
    glBindVertexArray(text_vao_);

    // 获取uniform变量位置
    GLint locScreenSize = glGetUniformLocation(text_program_, "uScreenSize");
    GLint locTextPos    = glGetUniformLocation(text_program_, "uTextPos");
    GLint locTextScale  = glGetUniformLocation(text_program_, "uTextScale");
    GLint locTextColor  = glGetUniformLocation(text_program_, "uTextColor");
    GLint locTextTex    = glGetUniformLocation(text_program_, "uTextTex");

    // 设置uniform变量
    glUniform2f(locScreenSize, (float)win_w_, (float)win_h_);
    glUniform1f(locTextScale, scale);
    glUniform3f(locTextColor, r, g, b);  // 使用提供的颜色

    float charX = x;
    // 直接使用屏幕坐标（左上角为原点，Y轴向下）
    // 着色器将处理到NDC的转换

    // 逐个字符渲染
    for (size_t i = 0; i < text.length(); i++) {
        char c = text[i];
        if (c >= '0' && c <= '9') {
            int digit = c - '0';
            // 使用亚像素定位以获得更平滑的文本渲染
            glUniform2f(locTextPos, charX, y);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, digit_textures_[digit]);
            glUniform1i(locTextTex, 0);
            glDrawArrays(GL_TRIANGLES, 0, 6);  // 绘制一个字符（两个三角形）
            charX += 8.0f * scale + 2.0f;     // 8像素宽度 + 2像素间距
        } else if (c == ' ') {
            charX += 8.0f * scale;            // 空格
        } else if (c == ',' || c == ':') {
            charX += 3.0f * scale;            // 标点符号间距
        }
    }

    glBindTexture(GL_TEXTURE_2D, 0);
    glBindVertexArray(0);
    glUseProgram(0);
}

// 渲染像素值：在放大的像素上显示RGB值
void ImageViewerOpenGL::renderPixelValues()
{
    if (original_image_.empty() || texture_ == 0) {
        std::cerr << "错误：renderPixelValues: 图像为空或纹理未准备好" << std::endl;
        return;
    }
    if (!text_program_) {
        std::cerr << "错误：renderPixelValues: text_program_ 未初始化！" << std::endl;
        return;
    }

    // 计算像素屏幕大小（每个图像像素占据多少个屏幕像素）
    // 这简单地就是缩放因子 - 每个图像像素以zoom_个屏幕像素显示
    float pixelScreenSize = (float)zoom_;

    // 首先根据像素屏幕大小确定是否应显示文本
    // 使用最小像素屏幕大小阈值（每个图像像素60个屏幕像素）
    // 这确保了无论窗口大小如何，文本都以相同的视觉大小出现
    // 重要：在计算可见像素范围之前检查此条件，因为窗口大小
    // 不影响像素屏幕大小，但确实影响可见像素数量
    float min_pixel_screen_size = 60.0f;
    if (pixelScreenSize < min_pixel_screen_size) {
        return;  // 如果像素在屏幕上不够大，则不渲染
    }

    // 计算可见像素范围
    int startX = static_cast<int>(std::max(0.0, std::floor(offset_x_)));
    int endX   = static_cast<int>(std::min((double)original_image_.cols, std::ceil(offset_x_ + win_w_ / zoom_)));
    int startY = static_cast<int>(std::max(0.0, std::floor(offset_y_)));
    int endY   = static_cast<int>(std::min((double)original_image_.rows, std::ceil(offset_y_ + win_h_ / zoom_)));

    // 为了性能，限制渲染到合理数量的像素
    // 此检查发生在像素屏幕大小检查之后
    // 当像素足够大（>= 每个图像像素60个屏幕像素）时，
    // 我们通常在屏幕上看到较少的像素，但如果窗口非常大，
    // 我们可能会看到更多。根据窗口大小相对于基准窗口大小来缩放限制。
    // 基准窗口大小：800x600
    double baseWindowArea    = 800.0 * 600.0;
    double currentWindowArea = (double)win_w_ * (double)win_h_;
    double pixelLimitScale   = std::max(1.0, currentWindowArea / baseWindowArea);
    int    maxPixels         = static_cast<int>(500 * pixelLimitScale);

    int visiblePixelCount = (endX - startX) * (endY - startY);
    if (visiblePixelCount > maxPixels) {
        // 像素太多，跳过渲染
        return;
    }

    // 根据像素大小缩放文本
    float textScale = std::min(1.5f, pixelScreenSize / 30.0f);

    // 为文本启用混合（确保已启用）
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glBlendEquation(GL_FUNC_ADD);

    // 禁用深度测试以确保文本在最上层
    glDisable(GL_DEPTH_TEST);

    // 遍历所有可见像素，为每个像素渲染RGB值
    for (int y = startY; y < endY; y++) {
        for (int x = startX; x < endX; x++) {
            // 计算像素中心在屏幕上的位置
            float pixelCenterX = (x + 0.5f - offset_x_) * zoom_;
            float pixelCenterY = (y + 0.5f - offset_y_) * zoom_;

            // 获取像素值
            if (original_image_.channels() == 3) {
                cv::Vec3b pixel = original_image_.at<cv::Vec3b>(y, x);
                // OpenCV以BGR格式存储，所以pixel[2]是R，pixel[1]是G，pixel[0]是B
                int r = (int)pixel[2];
                int g = (int)pixel[1];
                int b = (int)pixel[0];

                // 计算垂直布局的位置（R、G、B堆叠显示）
                float charWidth  = 8.0f * textScale + 2.0f;  // 字符宽度（包括间距）
                float rWidth     = std::to_string(r).length() * charWidth;
                float gWidth     = std::to_string(g).length() * charWidth;
                float bWidth     = std::to_string(b).length() * charWidth;
                float lineHeight = 10.0f * textScale + 1.0f;  // 行之间的高度（添加1像素间距）

                // 以最宽的数字为中心
                float maxWidth = std::max({rWidth, gWidth, bWidth});
                float startX   = pixelCenterX - maxWidth * 0.5f;

                // 在像素中心上方定位文本
                // 第一行：R（红色）在顶部
                float yPosR = pixelCenterY - lineHeight * 1.5f;
                // 第二行：G（绿色）在中间
                float yPosG = pixelCenterY - lineHeight * 0.5f;
                // 第三行：B（蓝色）在底部
                float yPosB = pixelCenterY + lineHeight * 0.5f;

                // 检查像素颜色是否匹配默认显示颜色，如果匹配则使用备用颜色
                // 默认颜色：R(217,0,34), G(0,230,100), B(0,109,240)
                // 备用颜色（当像素匹配默认颜色时）：R(236,97,109), G(74,190,68), B(64,173,211)
                // 检查像素RGB是否匹配任何默认显示颜色（在阈值内）
                const int colorMatchThreshold = 10;  // 允许10像素的差异用于颜色匹配

                // 检查像素颜色是否匹配默认R显示颜色 (217,0,34)
                bool matchesRColor = (std::abs(r - 217) <= colorMatchThreshold &&
                                      std::abs(g - 0) <= colorMatchThreshold &&
                                      std::abs(b - 34) <= colorMatchThreshold);

                // 检查像素颜色是否匹配默认G显示颜色 (0,230,100)
                bool matchesGColor = (std::abs(r - 0) <= colorMatchThreshold &&
                                      std::abs(g - 230) <= colorMatchThreshold &&
                                      std::abs(b - 100) <= colorMatchThreshold);

                // 检查像素颜色是否匹配默认B显示颜色 (0,109,240)
                bool matchesBColor = (std::abs(r - 0) <= colorMatchThreshold &&
                                      std::abs(g - 109) <= colorMatchThreshold &&
                                      std::abs(b - 240) <= colorMatchThreshold);

                // 根据颜色匹配确定文本颜色
                float rTextR, rTextG, rTextB;
                if (matchesRColor) {
                    // 像素匹配默认R颜色，对R数字使用备用颜色
                    rTextR = 236.0f / 255.0f;
                    rTextG = 97.0f / 255.0f;
                    rTextB = 109.0f / 255.0f;
                } else {
                    // 正常R显示颜色
                    rTextR = 217.0f / 255.0f;
                    rTextG = 0.0f / 255.0f;
                    rTextB = 34.0f / 255.0f;
                }

                float gTextR, gTextG, gTextB;
                if (matchesGColor) {
                    // 像素匹配默认G颜色，对G数字使用备用颜色
                    gTextR = 74.0f / 255.0f;
                    gTextG = 190.0f / 255.0f;
                    gTextB = 68.0f / 255.0f;
                } else {
                    // 正常G显示颜色
                    gTextR = 0.0f / 255.0f;
                    gTextG = 230.0f / 255.0f;
                    gTextB = 100.0f / 255.0f;
                }

                float bTextR, bTextG, bTextB;
                if (matchesBColor) {
                    // 像素匹配默认B颜色，对B数字使用备用颜色
                    bTextR = 64.0f / 255.0f;
                    bTextG = 173.0f / 255.0f;
                    bTextB = 211.0f / 255.0f;
                } else {
                    // 正常B显示颜色
                    bTextR = 0.0f / 255.0f;
                    bTextG = 109.0f / 255.0f;
                    bTextB = 240.0f / 255.0f;
                }

                // 绘制R值（第一行，居中）
                float rOffset = (maxWidth - rWidth) * 0.5f;
                drawTextAtScreenPos(startX + rOffset, yPosR, std::to_string(r), textScale, rTextR, rTextG, rTextB);

                // 绘制G值（第二行，居中）
                float gOffset = (maxWidth - gWidth) * 0.5f;
                drawTextAtScreenPos(startX + gOffset, yPosG, std::to_string(g), textScale, gTextR, gTextG, gTextB);

                // 绘制B值（第三行，居中）
                float bOffset = (maxWidth - bWidth) * 0.5f;
                drawTextAtScreenPos(startX + bOffset, yPosB, std::to_string(b), textScale, bTextR, bTextG, bTextB);
            } else if (original_image_.channels() == 1) {
                // 灰度图像：只显示单个灰度值
                uchar       val       = original_image_.at<uchar>(y, x);
                std::string text      = std::to_string((int)val);
                float       textWidth = text.length() * (8.0f * textScale + 2.0f);
                float       yPos      = pixelCenterY - 4.0f * textScale;  // 在像素中心上方定位
                
                // 根据像素灰度值动态调整文本颜色，确保与像素值有明显区分
                // 如果像素较暗（< 128），使用浅色文本（白色）；如果像素较亮（>= 128），使用深色文本（黑色）
                float textR, textG, textB;
                if (val < 160) {
                    // 像素较暗，使用浅色文本（白色）
                    textR = 1.0f;
                    textG = 1.0f;
                    textB = 1.0f;
                } else {
                    // 像素较亮，使用深色文本（黑色）
                    textR = 0.0f;
                    textG = 0.0f;
                    textB = 0.0f;
                }
                
                drawTextAtScreenPos(pixelCenterX - textWidth * 0.5f, yPos, text, textScale, textR, textG, textB);
            }
        }
    }

    glDisable(GL_BLEND);
}

// 获取像素边框颜色（如果有自定义则返回自定义颜色，否则返回默认颜色）
void ImageViewerOpenGL::getPixelBorderColor(int x, int y, float& r, float& g, float& b)
{
    std::lock_guard<std::mutex> lock(pixel_border_colors_mutex_);
    int key = y * original_image_.cols + x;
    auto it = pixel_border_colors_.find(key);
    if (it != pixel_border_colors_.end()) {
        r = std::get<0>(it->second);
        g = std::get<1>(it->second);
        b = std::get<2>(it->second);
    } else {
        r = default_border_color_[0];
        g = default_border_color_[1];
        b = default_border_color_[2];
    }
}

// 渲染像素网格：在放大时绘制像素边界线
void ImageViewerOpenGL::renderPixelGrid()
{
    if (original_image_.empty() || grid_program_ == 0)
        return;
    if (zoom_ < min_zoom_for_grid_)
        return;

    // 计算可见像素范围
    int startX = static_cast<int>(std::max(0.0, std::floor(offset_x_)));
    int endX   = static_cast<int>(std::min((double)original_image_.cols, std::ceil(offset_x_ + win_w_ / zoom_))) + 1;
    int startY = static_cast<int>(std::max(0.0, std::floor(offset_y_)));
    int endY   = static_cast<int>(std::min((double)original_image_.rows, std::ceil(offset_y_ + win_h_ / zoom_))) + 1;

    // 为了性能，限制网格线到合理数量
    int numLines = (endX - startX + 1) + (endY - startY + 1);
    if (numLines > 500) {
        return;  // 线条太多，跳过渲染
    }

    // 准备网格线顶点（每个顶点包含：位置(2个float) + 颜色(3个float) = 5个float）
    std::vector<float> vertices;
    vertices.reserve(numLines * 10);  // 每条线2个顶点，每个顶点5个float

    // 辅助函数：获取边的颜色（基于相邻像素的自定义颜色）
    auto getEdgeColor = [&](int x1, int y1, int x2, int y2, float& r, float& g, float& b) {
        // 获取两个相邻像素的边框颜色，取平均值
        float r1, g1, b1, r2, g2, b2;
        getPixelBorderColor(x1, y1, r1, g1, b1);
        getPixelBorderColor(x2, y2, r2, g2, b2);
        r = (r1 + r2) * 0.5f;
        g = (g1 + g2) * 0.5f;
        b = (b1 + b2) * 0.5f;
    };

    // 垂直线（x = 常数，连接像素的左右边界）
    // 将每条垂直线分割成多个线段，每个线段对应一个像素边界
    for (int x = startX; x <= endX; x++) {
        float imgX = (float)x;
        
        // 为每个像素行创建线段
        for (int y = startY; y < endY; y++) {
            float r, g, b;
            
            // 获取这条边的颜色（基于 x-1 和 x 列的像素）
            if (x > 0 && x < original_image_.cols) {
                // 使用当前 y 位置的像素颜色，而不是中间位置
                getEdgeColor(x - 1, y, x, y, r, g, b);
            } else {
                // 边界情况，使用默认颜色
                r = default_border_color_[0];
                g = default_border_color_[1];
                b = default_border_color_[2];
            }
            
            // 添加线段的两个顶点（从 y 到 y+1）
            vertices.push_back(imgX);           // x
            vertices.push_back((float)y);       // y (起点)
            vertices.push_back(r);              // r
            vertices.push_back(g);              // g
            vertices.push_back(b);             // b
            
            vertices.push_back(imgX);           // x
            vertices.push_back((float)(y + 1)); // y+1 (终点)
            vertices.push_back(r);              // r
            vertices.push_back(g);              // g
            vertices.push_back(b);             // b
        }
    }

    // 水平线（y = 常数，连接像素的上下边界）
    // 将每条水平线分割成多个线段，每个线段对应一个像素边界
    for (int y = startY; y <= endY; y++) {
        float imgY = (float)y;
        
        // 为每个像素列创建线段
        for (int x = startX; x < endX; x++) {
            float r, g, b;
            
            // 获取这条边的颜色（基于 y-1 和 y 行的像素）
            if (y > 0 && y < original_image_.rows) {
                // 使用当前 x 位置的像素颜色，而不是中间位置
                getEdgeColor(x, y - 1, x, y, r, g, b);
            } else {
                // 边界情况，使用默认颜色
                r = default_border_color_[0];
                g = default_border_color_[1];
                b = default_border_color_[2];
            }
            
            // 添加线段的两个顶点（从 x 到 x+1）
            vertices.push_back((float)x);       // x (起点)
            vertices.push_back(imgY);           // y
            vertices.push_back(r);              // r
            vertices.push_back(g);              // g
            vertices.push_back(b);             // b
            
            vertices.push_back((float)(x + 1)); // x+1 (终点)
            vertices.push_back(imgY);           // y
            vertices.push_back(r);              // r
            vertices.push_back(g);              // g
            vertices.push_back(b);             // b
        }
    }

    if (vertices.empty())
        return;

    // 使用网格着色器程序
    glUseProgram(grid_program_);

    // 设置uniform变量
    GLint locWin   = glGetUniformLocation(grid_program_, "uWinSize");
    GLint locImg   = glGetUniformLocation(grid_program_, "uImgSize");
    GLint locOff   = glGetUniformLocation(grid_program_, "uOffset");
    GLint locZoom  = glGetUniformLocation(grid_program_, "uZoom");

    float imgW = (float)original_image_.cols;
    float imgH = (float)original_image_.rows;

    glUniform2f(locWin, (float)win_w_, (float)win_h_);
    glUniform2f(locImg, imgW, imgH);
    glUniform2f(locOff, (float)offset_x_, (float)offset_y_);
    glUniform1f(locZoom, (float)zoom_);

    // 上传顶点数据（包含位置和颜色）
    glBindVertexArray(grid_vao_);
    glBindBuffer(GL_ARRAY_BUFFER, grid_vbo_);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_DYNAMIC_DRAW);

    // 绘制线条
    glLineWidth(1.0f);
    glDrawArrays(GL_LINES, 0, vertices.size() / 5);  // 每个顶点5个float

    glBindVertexArray(0);
    glUseProgram(0);
}

// 设置指定像素的边框颜色
void ImageViewerOpenGL::setPixelBorderColor(int x, int y, float r, float g, float b)
{
    if (original_image_.empty())
        return;
    if (x < 0 || x >= original_image_.cols || y < 0 || y >= original_image_.rows)
        return;
    
    std::lock_guard<std::mutex> lock(pixel_border_colors_mutex_);
    int key = y * original_image_.cols + x;
    pixel_border_colors_[key] = std::make_tuple(r, g, b);
}

// 清除指定像素的自定义边框颜色（恢复默认）
void ImageViewerOpenGL::clearPixelBorderColor(int x, int y)
{
    if (original_image_.empty())
        return;
    if (x < 0 || x >= original_image_.cols || y < 0 || y >= original_image_.rows)
        return;
    
    std::lock_guard<std::mutex> lock(pixel_border_colors_mutex_);
    int key = y * original_image_.cols + x;
    pixel_border_colors_.erase(key);
}

// 清除所有自定义边框颜色（恢复默认）
void ImageViewerOpenGL::clearAllPixelBorderColors()
{
    std::lock_guard<std::mutex> lock(pixel_border_colors_mutex_);
    pixel_border_colors_.clear();
}

// 设置默认边框颜色
void ImageViewerOpenGL::setDefaultBorderColor(float r, float g, float b)
{
    default_border_color_[0] = r;
    default_border_color_[1] = g;
    default_border_color_[2] = b;
}

// 设置窗口位置
void ImageViewerOpenGL::setWindowPosition(int x, int y)
{
    win_x_ = x;
    win_y_ = y;
    // 如果窗口已创建，立即更新位置
    if (window_ && x >= 0 && y >= 0) {
        glfwSetWindowPos(window_, x, y);
    }
}

// ==================== ImageViewer 包装类的方法 ====================

// 辅助函数：查找窗口（支持原始名称和带 " (bind)" 的名称）
std::map<std::string, std::unique_ptr<WindowInfo>>::iterator 
ImageViewer::findWindow(const std::string& window_name)
{
    // 首先尝试直接查找
    auto it = windows_.find(window_name);
    if (it != windows_.end()) {
        return it;
    }
    
    // 如果找不到，尝试查找带 " (bind)" 后缀的版本
    std::string bind_window_name = window_name + " (bind)";
    it = windows_.find(bind_window_name);
    if (it != windows_.end()) {
        return it;
    }
    
    // 如果还找不到，尝试去掉 " (bind)" 后缀（以防用户传入带后缀的名称）
    if (window_name.length() > 7 && window_name.substr(window_name.length() - 7) == " (bind)") {
        std::string original_name = window_name.substr(0, window_name.length() - 7);
        it = windows_.find(original_name);
        if (it != windows_.end()) {
            return it;
        }
    }
    
    return windows_.end();
}

// 设置指定窗口的像素边框颜色
void ImageViewer::setPixelBorderColor(const std::string& window_name, int x, int y, float r, float g, float b)
{
    std::lock_guard<std::mutex> lock(windows_mutex_);
    auto it = findWindow(window_name);
    if (it != windows_.end() && it->second->viewer) {
        it->second->viewer->setPixelBorderColor(x, y, r, g, b);
    }
}

// 清除指定窗口的像素自定义边框颜色
void ImageViewer::clearPixelBorderColor(const std::string& window_name, int x, int y)
{
    std::lock_guard<std::mutex> lock(windows_mutex_);
    auto it = findWindow(window_name);
    if (it != windows_.end() && it->second->viewer) {
        it->second->viewer->clearPixelBorderColor(x, y);
    }
}

// 清除指定窗口的所有自定义边框颜色
void ImageViewer::clearAllPixelBorderColors(const std::string& window_name)
{
    std::lock_guard<std::mutex> lock(windows_mutex_);
    auto it = findWindow(window_name);
    if (it != windows_.end() && it->second->viewer) {
        it->second->viewer->clearAllPixelBorderColors();
    }
}

// 设置指定窗口的默认边框颜色
void ImageViewer::setDefaultBorderColor(const std::string& window_name, float r, float g, float b)
{
    std::lock_guard<std::mutex> lock(windows_mutex_);
    auto it = findWindow(window_name);
    if (it != windows_.end() && it->second->viewer) {
        it->second->viewer->setDefaultBorderColor(r, g, b);
    }
}

// 设置指定窗口的位置
void ImageViewer::setWindowPosition(const std::string& window_name, int x, int y)
{
    std::lock_guard<std::mutex> lock(windows_mutex_);
    auto it = findWindow(window_name);
    if (it != windows_.end() && it->second->viewer) {
        // 窗口已创建，设置位置并立即更新
        it->second->viewer->setWindowPosition(x, y);
    }
    // 注意：如果窗口还未创建，需要在 showImage 之后调用此方法
    // 或者可以在 showImage 之前设置，但需要在窗口创建时传递位置信息
    // 当前实现支持在窗口创建后设置位置
}

// 同步视图状态到绑定组中的其他窗口
void ImageViewerOpenGL::syncViewStateToBindGroup()
{
    if (bind_name_.empty() || is_syncing_ || !window_info_)
        return;
    
    is_syncing_ = true;
    
    ImageViewer* parent = window_info_->parent_viewer;
    if (!parent)
    {
        is_syncing_ = false;
        return;
    }
    
    std::lock_guard<std::mutex> lock(parent->windows_mutex_);
    
    // 查找绑定组
    auto bind_it = parent->bind_groups_.find(bind_name_);
    if (bind_it == parent->bind_groups_.end())
    {
        is_syncing_ = false;
        return;
    }
    
    // 同步到绑定组中的其他窗口
    for (const std::string& other_window_name : bind_it->second)
    {
        if (other_window_name == window_name_)
            continue;  // 跳过自己
        
        auto win_it = parent->windows_.find(other_window_name);
        if (win_it != parent->windows_.end() && win_it->second->viewer)
        {
            win_it->second->viewer->syncViewStateFromOther(zoom_, offset_x_, offset_y_);
        }
    }
    
    is_syncing_ = false;
}

// 从其他窗口同步视图状态
void ImageViewerOpenGL::syncViewStateFromOther(double zoom, double offset_x, double offset_y)
{
    if (is_syncing_)
        return;
    
    is_syncing_ = true;
    
    // 更新视图状态
    zoom_ = zoom;
    offset_x_ = offset_x;
    offset_y_ = offset_y;
    
    // 应用边界限制
    double scaledImgW = original_image_.cols * zoom_;
    double scaledImgH = original_image_.rows * zoom_;
    
    bool imageSmallerThanWindowW = (scaledImgW < win_w_);
    bool imageSmallerThanWindowH = (scaledImgH < win_h_);
    
    double imgCenterX = original_image_.cols * 0.5;
    double imgCenterY = original_image_.rows * 0.5;
    double winCenterX = win_w_ * 0.5;
    double winCenterY = win_h_ * 0.5;
    
    if (imageSmallerThanWindowW && imageSmallerThanWindowH) {
        offset_x_ = imgCenterX - winCenterX / zoom_;
        offset_y_ = imgCenterY - winCenterY / zoom_;
    } else {
        if (imageSmallerThanWindowW) {
            offset_x_ = imgCenterX - winCenterX / zoom_;
        }
        if (imageSmallerThanWindowH) {
            offset_y_ = imgCenterY - winCenterY / zoom_;
        }
        
        if (!imageSmallerThanWindowW) {
            double maxOx = std::max(0.0, (double)original_image_.cols - win_w_ / zoom_);
            if (offset_x_ < 0)
                offset_x_ = 0;
            if (offset_x_ > maxOx)
                offset_x_ = maxOx;
        }
        if (!imageSmallerThanWindowH) {
            double maxOy = std::max(0.0, (double)original_image_.rows - win_h_ / zoom_);
            if (offset_y_ < 0)
                offset_y_ = 0;
            if (offset_y_ > maxOy)
                offset_y_ = maxOy;
        }
    }
    
    is_syncing_ = false;
}

}  // namespace toolsLib

